home *** CD-ROM | disk | FTP | other *** search
- // File "sysmenu.c" - Sample shell for creating and installing your own System Menu
- // from a system extension. <fprefect@umich.edu>, 2/26/95
- // Can be compiled under CW8 as 68k INIT Code Rsrc (System Heap)
- //
- // * Modified 4/20/96 (MJS) - Updated for CW8
- // Updated enclosed INIT Dispatcher to 1.3
- // Improved ResError checking
- //
- // * Modified 12/5/95 (MJS) - Rebuilt for CW7 Code Rsrc structure, simplifying and
- // combining if possible. Same code for 68k and PPC.
- // - Fixed A4-global access at end of SystemMenu patch.
- //
- // * Modified 7/25/95 (MJS) - Restructured to work under CW6
- //
- // * Modified 3/12/95 (MJS) - Added InsertMenu patch to support dynamic menu numbering.
-
- // * ******************************************************************************* *
-
- #include <A4Stuff.h>
- #include <Gestalt.h>
- #include <Icons.h>
- #include <Traps.h>
-
- #include "sysmenu.h"
- #include "patches.h"
-
- //#define ____DEBUG____
- #define k68KProcType '68K•'
- #define kPPCProcType 'PPC•'
-
- // * ******************************************************************************* *
- // Global Declarations
-
- GlobalsRec glob;
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- void main() {
- long saveA4, response;
- Handle myHandle;
-
- #ifdef ____DEBUG____
- // Test for the option key - Beep, but dont load
- if ((* (((char *) 0x0174) + 7)) & 0x04) {
- SysBeep(7);
- return;
- }
- #endif ____DEBUG____
-
- saveA4 = SetCurrentA4();
-
- // Determine the environment and prepare our code
- if (Gestalt(gestaltSystemVersion, &response) || (response < 0x0700)) goto PROC_END;
- myHandle = Get1Resource((GetCurrentISA() == kPowerPCISA) ?
- kPPCProcType : k68KProcType, 0);
- if (!myHandle || ResError()) goto PROC_END;
- DetachResource(myHandle);
- if (ResError()) goto PROC_END;
-
- // Setup Global Data
- SetZone(SystemZone());
-
- // Setup Handlers
- glob.saveInsertMenu = ApplyTrapPatch(_InsertMenu,
- (ProcPtr) NewInsertMenuProc(Patched_InsertMenu));
- glob.saveDrawMenuBar = ApplyTrapPatch(_DrawMenuBar,
- (ProcPtr) NewDrawMenuBarProc(Patched_DrawMenuBar));
- glob.saveMenuSelect = ApplyTrapPatch(_MenuSelect,
- (ProcPtr) NewMenuSelectProc(Patched_MenuSelect));
- glob.saveSystemMenu = ApplyTrapPatch(_SystemMenu,
- (ProcPtr) NewSystemMenuProc(Patched_SystemMenu));
-
- glob.mHdl = 0;
- glob.menuID = 0;
- glob.menuIcon = 0;
- glob.sysMenus = (short **) NewHandle(0);
-
- // Load up our icon suite for the menu "title" (if the iconID is non-zero)
- // Get *all* icons in case the desired size (12x12) isn't available.
- if (kPrefIconID && ! GetIconSuite(&myHandle, kPrefIconID, svAllAvailableData) &&
- ! ForEachIconDo(myHandle, svAllAvailableData, NewIconActionProc(DetachIcons), 0))
- glob.menuIcon = myHandle;
-
- // Remember the location of our home rsrc file, in case we want to
- // load an dialog or other resource at run-time. Note: this doesn't provide
- // any guarantee that the file will be there later, so check your errors!
- if (CurResFileAsFSSpec(&glob.homeFile)) glob.homeFile.vRefNum = 0;
-
- SetZone(ApplicZone());
-
- PROC_END:
- SetA4(saveA4);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- short CurResFileAsFSSpec(FSSpec *fileSpec) {
- short i, err=0;
- Str63 textBuff;
- FCBPBRec fcbPB;
-
- for(i=0; i<sizeof(FSSpec); ((char *) fileSpec)[i++]=0);
-
- fcbPB.ioCompletion = 0;
- fcbPB.ioFCBIndx = 0;
- fcbPB.ioVRefNum = 0;
- fcbPB.ioRefNum = CurResFile();
- fcbPB.ioNamePtr = textBuff;
- if (err = PBGetFCBInfoSync(&fcbPB)) return(err);
-
- fileSpec->vRefNum = fcbPB.ioFCBVRefNum;
- fileSpec->parID = fcbPB.ioFCBParID;
- BlockMove(textBuff, fileSpec->name, textBuff[0]+1);
-
- return(err);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- ProcPtr ApplyTrapPatch(short trap, ProcPtr patchPtr) {
- ProcPtr trapPtr;
-
- if (! patchPtr) return(0);
-
- trapPtr = (ProcPtr) NGetTrapAddress(trap, (trap & 0x0800) ? ToolTrap : OSTrap);
- NSetTrapAddress((UniversalProcPtr) patchPtr, trap, (trap & 0x0800) ? ToolTrap : OSTrap);
- return(trapPtr);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- pascal short DetachIcons(long iconType, Handle *iconHdl, void *data) {
- short err=0;
-
- if (*iconHdl) {
- DetachResource(*iconHdl);
- HNoPurge(*iconHdl);
- err = ResError();
- }
- return(err);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
- #pragma mark -
-
- pascal void Patched_InsertMenu(MenuHandle mHdl, short beforeID) {
- short menuID = (*mHdl)->menuID;
- long saveA4;
- ProcPtr proc;
-
- saveA4 = SetCurrentA4();
-
- #ifdef ____DEBUG____
- Debugger();
- #endif ____DEBUG____
-
- // As suggested to me, we need a reliable way to track what menus
- // have been installed, so we can pick a unique ID for ours. This
- // function simply tracks the ID's to a global variable.
- if (! glob.menuID && glob.sysMenus && (menuID < 0))
- PtrAndHand((Ptr) &menuID, (Handle) glob.sysMenus, sizeof(menuID));
-
- proc = glob.saveInsertMenu;
- SetA4(saveA4);
- CallInsertMenuProc(proc, mHdl, beforeID);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- pascal void Patched_DrawMenuBar() {
- short i, found;
- long saveA4;
- ProcPtr proc;
- Str32 textBuff;
- THz saveZone;
-
- saveA4 = SetCurrentA4();
-
- if (! glob.mHdl) {
- // On the first chance, we create and install the new menu
- // (We need to wait for the Menu Mgr to be initialized to setup)
-
- #ifdef ____DEBUG____
- Debugger();
- #endif ____DEBUG____
-
- // Let's not create the menu in this App's heap
- saveZone = GetZone();
- SetZone(SystemZone());
-
- // Search for an unused Menu ID, then install the menu. We have tracked
- // the InsertMenu calls, so now we pick an ID not in that list. When done
- // we set the gMenuID and dispose (and clear) the gSysMenus handle.
- for(glob.menuID = kPrefMenuID; ; glob.menuID++) {
- i=GetHandleSize((Handle) glob.sysMenus) / sizeof(**glob.sysMenus);
- for(found = 0; !found && (i>0);
- found = ((*glob.sysMenus)[--i] == glob.menuID));
- if (! found) {
- DisposeHandle((Handle) glob.sysMenus);
- glob.sysMenus = 0;
- break;
- }
- }
-
- // Setup our new menu with its (optional) cool icon
- if (glob.menuIcon) {
- textBuff[0]=5;
- textBuff[1]=1;
- BlockMove(&glob.menuIcon, textBuff+2, sizeof(glob.menuIcon));
- }
- else BlockMove("\pMenu", textBuff, sizeof("\pMenu"));
- glob.mHdl = NewMenu(glob.menuID, textBuff);
-
- // For this example, we build it from scratch. I prefer making the
- // AppendMenu() call with dummy args *then* SetItem() with our item.
- // If you trust AppendMenu() with raw data, it will interpret the Menu
- // Managers meta-chars ("-"=Separator, "("=Disabled, "/B"=Command-B, etc)
- AppendMenu(glob.mHdl, "\p ");
- SetItem(glob.mHdl, CountMItems(glob.mHdl), "\pAbout SysMenu...");
- AppendMenu(glob.mHdl, "\p-");
- AppendMenu(glob.mHdl, "\p ");
- SetItem(glob.mHdl, CountMItems(glob.mHdl), "\pItem 1");
- AppendMenu(glob.mHdl, "\p ");
- SetItem(glob.mHdl, CountMItems(glob.mHdl), "\pItem 2");
- AppendMenu(glob.mHdl, "\p ");
- SetItem(glob.mHdl, CountMItems(glob.mHdl), "\pItem 3");
- AppendMenu(glob.mHdl, "\p ");
- SetItem(glob.mHdl, CountMItems(glob.mHdl), "\pItem 4");
-
- InsertMenu(glob.mHdl, 0);
-
- SetZone(saveZone);
- }
- proc = glob.saveDrawMenuBar;
- SetA4(saveA4);
- CallDrawMenuBarProc(proc);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- pascal long Patched_MenuSelect(Point where) {
- long saveA4, value;
- ProcPtr proc;
-
- saveA4 = SetCurrentA4();
-
- #ifdef ____DEBUG____
- Debugger();
- #endif ____DEBUG____
-
- // This function is called when the user first clicks in the menubar.
- // Its an ideal place to update the contents of your menu on the fly
- // to reflect current settings or conditions.
-
- // You should comment out this patch if you dont use the hook.
-
- proc = glob.saveMenuSelect;
- SetA4(saveA4);
- value = CallMenuSelectProc(proc, where);
- return(value);
- }
-
- // * ******************************************************************************* *
- // * ******************************************************************************* *
-
- pascal void Patched_SystemMenu(long result) {
- short menuID, itemID, compareID;
- long saveA4;
- ProcPtr proc;
-
- saveA4 = SetCurrentA4();
-
- menuID = (result & 0xFFFF0000) >> 16;
- itemID = result & 0x0000FFFF;
- compareID = glob.menuID;
-
- // When the user has selected a menu item (by mouse or cmd-key)
- // we scan the event and handle it if it is from our menu.
- if (menuID == compareID) {
-
- #ifdef ____DEBUG____
- Debugger();
- #endif ____DEBUG____
-
- // Some apps aren't careful about giving us the arrow.
- InitCursor();
-
- switch(itemID) {
- case 1:
- SysBeep(7);
- break;
- default:
- SysBeep(7);
- SysBeep(7);
- break;
- }
-
- // I don't think this is vital, but may be helpful for handlers
- // that go into a GNE loop (such as Alert() or ModalDialog())
- HiliteMenu(0);
- }
-
- proc = glob.saveSystemMenu;
- SetA4(saveA4);
- // Otherwise, pass it on!
- if (menuID != compareID) CallSystemMenuProc(proc, result);
- }
-
-